package consumer

import (
	"log"
	"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
	if err != nil {
		log.Fatalf("%s: %s", msg, err)
	}
}

// host "amqp://admin:admin@192.168.10.138:5672/"
func Consumer(host string, exchangeName string, routings []string) {
	conn, err := amqp.Dial(host)
	failOnError(err, "Failed to connect to RabbitMQ")
	defer conn.Close()

	//创建一个channel来传递消息
	ch, err := conn.Channel()
	failOnError(err, "Failed to open a channel")
	defer ch.Close()

	// 声明一个交换机
	err = ch.ExchangeDeclare(
		exchangeName, // name 交换机名称
		"topic",      // type 主题交换机
		true,         // durable 持久化
		false,        // auto-deleted
		false,        // internal
		false,        // no-wait
		nil,          // arguments
	)
	failOnError(err, "Failed to declare an exchange")

	// 声明一个队列 exclusive
	//首先，当我们连接上RabbitMQ的时候，我们需要一个全新的、空的队列。我们可以手动创建一个随机的队列名，或者让服务器为我们选择一个随机的队列名（推荐）。
	//其次，当与消费者（consumer）断开连接的时候，这个队列应当被立即删除。 在amqp客户端中，当我们将队列名称作为空字符串提供时，我们创建一个具有生成名称的非持久队列：
	q, err := ch.QueueDeclare(
		"",    // name
		false, // durable
		false, // delete when usused
		true,  // exclusive
		false, // no-wait
		nil,   // arguments
	)
	failOnError(err, "Failed to declare a queue")

	//交换器和队列之间的联系我们称之为绑定（binding）。
	// 可以简单理解为：这个队列（queue）对这个交换机（exchange）的消息感兴趣。
	for _, routing := range routings {
		log.Printf("Binding queue %s to exchange %s with routing key %s",
			q.Name, exchangeName, routing)
		err = ch.QueueBind(
			q.Name,       // 队列名称
			routing,      // routing key
			exchangeName, // exchange
			false,
			nil)
		failOnError(err, "Failed to bind a queue")
	}

	// 消费者
	msgs, err := ch.Consume(
		q.Name, // queue
		"",     // consumer
		true,   // auto ack 消息确认
		false,  // exclusive
		false,  // no local
		false,  // no wait
		nil,    // args
	)
	failOnError(err, "Failed to register a consumer")

	forever := make(chan bool)

	go func() {
		log.Printf("Waiting for msgs")
		for d := range msgs {
			log.Printf(" [x] Consumer %s", d.Body)
		}
	}()

	log.Printf(" [*] Waiting for msgs. To exit press CTRL+C")
	<-forever
	log.Printf(" Consumer stop")
}
